package comunicacao;

import comunicacao.Mensagem;
import comunicacao.DestinoDesconhecidoException;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Iterator;
import java.util.LinkedList;

import fachada.Fachada;

public class ServidorTCP implements Comunicacao {
	private ServerSocket serverSocket;
	private LinkedList<Conexao> conexoes;
	private ThreadAceitarConexao threadAceitarConexao;
	private ThreadReceberSolicitacaoServico servico;
	private Fachada fachada;
	private String nomePartida;
	private int numParticipantes;
	
	public ServidorTCP(int port, Fachada fachada, String nomePartida, int numParticipantes) throws IOException {
		this.serverSocket = new ServerSocket(port);
		this.conexoes = new LinkedList<Conexao>();
		this.threadAceitarConexao = new ThreadAceitarConexao(this);
		this.threadAceitarConexao.start();
		this.servico = new ThreadReceberSolicitacaoServico(this);
		this.servico.start();
		this.fachada = fachada;
		this.setNomePartida(nomePartida);
		this.setNumParticipantes(numParticipantes);
	}
	
	@Override
	public void enviar(Mensagem mensagem) throws DestinoDesconhecidoException, IOException {
		ObjectOutputStream output;
		Conexao conexao;
		Iterator<String> iterador;
		if(mensagem instanceof MensagemConfirmarParticipacao) {
			conexao = buscarConexao(mensagem.getDestinos().getFirst());
			conexao.setAceite(true);
		}if(mensagem instanceof MensagemInformacoesServico) {
			MensagemInformacoesServico m = (MensagemInformacoesServico)mensagem;
			Socket s = new Socket(m.getDestinos().getFirst(), 8888);
			output = new ObjectOutputStream(s.getOutputStream());
			output.writeObject(m);
		} else {
			iterador = mensagem.getDestinos().iterator();
			while (iterador.hasNext()) {
				String cor = iterador.next();
				conexao = buscarConexao(cor);
				if (conexao != null) {
					output = new ObjectOutputStream(conexao.getSocket()
							.getOutputStream());
					output.writeObject(mensagem);
				} else {
					throw new DestinoDesconhecidoException(cor);
				}
			}
		}
	}
	
	@Override
	public void receber(Mensagem mensagem) throws DestinoDesconhecidoException, IOException {
		if(mensagem instanceof MensagemParticiparJogo) {
			String cor;
			Conexao conexao;
			cor = ((MensagemParticiparJogo) mensagem).getCor();
			conexao = buscarConexao(Conexao.SEMROTULO);
			if(conexao != null) {
				conexao.setRotulo(cor);
				this.fachada.adicionarjogador(cor);
			}
			else {
				System.out.println("Conexao desconecida! De: " + mensagem.getOrigem());
			}
		}
		if(mensagem instanceof MensagemRodarDados) {
			this.fachada.rodarDados();
		}
		if(mensagem instanceof MensagemComprar) {
			this.fachada.comprar();
		}
		if(mensagem instanceof MensagemPassarVez) {
			this.fachada.passarVez();
		}
		if(mensagem instanceof MensagemChat) {
			this.fachada.enviarMsgChat(mensagem);
		}if(mensagem instanceof MensagemSairPartida) {
			fecharConexao(mensagem.getOrigem());
		}if(mensagem instanceof MensagemVez){
			this.fachada.jogarNovamente();
		}
	}
	
	@SuppressWarnings("deprecation")
	private void fecharConexao(String adress) throws IOException, DestinoDesconhecidoException{
		Conexao conexao;
		conexao = buscarConexao(adress);
		if(conexao != null) {
			conexao.getThreadReceberMensagem().stop();
			conexao.getSocket().close();
			this.conexoes.remove(conexao);
			
			if(this.conexoes.size() == 1){
				declararVencedor();
			}
		}
		else {
			System.out.println("Conexao desconecida! De: " + adress);
		}
	}
	
	private void declararVencedor() throws UnknownHostException, DestinoDesconhecidoException, IOException{
		String destino = conexoes.get(0).getSocket().getInetAddress().getHostAddress();
		this.enviar(new MensagemFimDeJogo(destino,
				InetAddress.getLocalHost().getHostAddress()));
	}
	
	private Conexao buscarConexao(String identificador){
		Iterator<Conexao> iterador = this.conexoes.iterator();
		Conexao conexao;
		while(iterador.hasNext()){
			conexao = iterador.next();
			if(conexao.getRotulo().equals(identificador) || 
					conexao.getSocket().getInetAddress().getHostAddress().equals(identificador)){
				return conexao;
			}
		}
		return null;
	}
	
	public ServerSocket getServerSocket() {
		return this.serverSocket;
	}

	public void setServerSocket(ServerSocket serverSocket) {
		this.serverSocket = serverSocket;
	}

	public ThreadAceitarConexao getThreadAceitarConexao() {
		return this.threadAceitarConexao;
	}

	public void setThreadAceitarConexao(ThreadAceitarConexao threadAceitarConexao) {
		this.threadAceitarConexao = threadAceitarConexao;
	}

	public LinkedList<Conexao> getConexoes() {
		return this.conexoes;
	}

	public void setConexoes(LinkedList<Conexao> conexoes) {
		this.conexoes = conexoes;
	}

	public Fachada getFachada() {
		return this.fachada;
	}

	public void setFachada(Fachada fachada) {
		this.fachada = fachada;
	}

	public String getNomePartida() {
		return nomePartida;
	}

	public void setNomePartida(String nomePartida) {
		this.nomePartida = nomePartida;
	}

	public int getNumParticipantes() {
		return numParticipantes;
	}

	public void setNumParticipantes(int numParticipantes) {
		this.numParticipantes = numParticipantes;
	}

	@Override
	public void close() throws DestinoDesconhecidoException, IOException {
		System.out.println("Servidor desconectado");
		//tratar
	}
	
	
}
